//
// https://blog.csdn.net/chenrenxiang/article/details/80291224
// https://futurestud.io/tutorials/gson-builder-basics-naming-policies#3
//

package addition;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.google.gson.annotations.SerializedName;
import com.google.gson.reflect.TypeToken;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.junit.Test;

import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class GsonDemo {

    // 序列化：将 User 对象序列化为 Json 字符串
    @Test
    public void test1() {
        final Gson gson = new Gson();
        final User user = new User("Chisheng Chen", "chisheng@163.com", 20, true);
        final String userJsonString = gson.toJson(user);
        System.out.println(userJsonString);
        // {"name":"Chisheng Chen","email":"chisheng@163.com","age":20,"isDeveloper":true}
    }

    // 反序列化：将 Json 字符串反序列化为 User 对象
    @Test
    public void test2() {
        final Gson gson = new Gson();
        final String userJsonString = "{\"name\":\"Chisheng Chen\",\"email\":\"chisheng@163.com\",\"age\":20,\"isDeveloper\":true}";
        final User user = gson.fromJson(userJsonString, User.class);
        System.out.println(user);
        // GsonDemo.User(name=Chisheng Chen, email=chisheng@163.com, age=20, isDeveloper=true)
    }

    // 复杂对象序列化 / 反序列化
    @Test
    public void test3() {
        final Gson gson = new Gson();
        final ComplexUser complexUser = new ComplexUser("Chisheng Chen", "chisheng@163.com", 20, true,
                new Address("China", "Mengzi", "Honghe University"));
        final String complexUserJsonString = gson.toJson(complexUser);
        System.out.println(complexUserJsonString);
        // {"name":"Chisheng Chen","email":"chisheng@163.com","age":20,"isDeveloper":true,"address":{"nation":"China","city":"Mengzi","street":"Honghe University"}}
        final ComplexUser deserializableComplexUser = gson.fromJson(complexUserJsonString, ComplexUser.class);
        System.out.println(deserializableComplexUser);
        // GsonDemo.ComplexUser(name=Chisheng Chen, email=chisheng@163.com, age=20, isDeveloper=true, address=GsonDemo.Address(nation=China, city=Mengzi, street=Honghe University))
    }

    // 数组的序列化 / 反序列化
    @Test
    public void test4() {
        final Gson gson = new Gson();
        final double[] array = new double[]{3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.20};
        final String arrayJsonString = gson.toJson(array);
        System.out.println(arrayJsonString);
        // [3.14,3.15,3.16,3.17,3.18,3.19,3.2]
        final double[] deserializableArray = gson.fromJson(arrayJsonString, double[].class);
        System.out.println(Arrays.toString(deserializableArray));
        // [3.14, 3.15, 3.16, 3.17, 3.18, 3.19, 3.2]
    }

    // List 的序列化 / 反序列化
    @Test
    public void test5() {
        final Gson gson = new Gson();
        final List<String> list = List.of("Zhangsan", "Lissi", "Wing", "Liming");
        final String listJsonString = gson.toJson(list);
        System.out.println(listJsonString);
        // ["Zhangsan","Lissi","Wing","Liming"]

        // 创建 List<String> 类型 Type
        final Type listType = new TypeToken<List<String>>() {
        }.getType();
        final List<String> deserializableList = gson.fromJson(listJsonString, listType);
        System.out.println(deserializableList);
        // [Zhangsan, Lissi, Wing, Liming]
    }

    // Map 的序列化 / 反序列化
    @Test
    public void test6() {
        final Gson gson = new Gson();
        final Map<String, List<String>> map = Map.of("zhangsan", List.of("pupil", "boy", "sunshine"), "litchi", List.of("teacher", "professor"));
        final String mapJsonString = gson.toJson(map);
        System.out.println(mapJsonString);
        // {"zhangsan":["pupil","boy","sunshine"],"litchi":["teacher","professor"]}
        final Type mapType = new TypeToken<Map<String, List<String>>>() {
        }.getType();
        final Map<String, List<String>> deserializableMap = gson.fromJson(mapJsonString, mapType);
        System.out.println(deserializableMap);
        // {zhangsan=[pupil, boy, sunshine], litchi=[teacher, professor]}
    }

    // null 参与的序列化与反序列化
    @Test
    public void test7() {
        final Gson gson = new Gson();
        final User user = new User("Chisheng Chen", null, 20, false);
        final String userJsonString = gson.toJson(user);
        System.out.println(userJsonString);
        // null value is disappear
        // {"name":"Chisheng Chen","age":20,"isDeveloper":false}
        final User deserializableUser = gson.fromJson(userJsonString, User.class);
        System.out.println(deserializableUser);
        // GsonDemo.User(name=Chisheng Chen, email=null, age=20, isDeveloper=false)
    }

    // 控制序列化 / 反序列化的变量名称
    @Test
    public void test8() {
        final Gson gson = new Gson();
        final VariousUser user = new VariousUser("Chisheng Chen", "chisheng@163.com", 20, true);
        final String userJsonString = gson.toJson(user);
        System.out.println(userJsonString);
        // {"fullName":"Chisheng Chen","email":"chisheng@163.com","age":20,"isDeveloper":true}
        final VariousUser deserializableVariousUser = gson.fromJson(userJsonString, VariousUser.class);
        System.out.println(deserializableVariousUser);
        // GsonDemo.VariousUser(name=Chisheng Chen, email=chisheng@163.com, age=20, isDeveloper=true)
    }

    // 序列化 / 反序列化过程中忽略某些变量
    @Test
    public void test9() {
        // Create Gson Object By Gson Builder
        final GsonBuilder gsonBuilder = new GsonBuilder();
        // As such method name, exclude filed without expose annotation
        gsonBuilder.excludeFieldsWithoutExposeAnnotation();
        final Gson gson = gsonBuilder.create();
        final IgnoreUser ignoreUser = new IgnoreUser("Chisheng Chen", "chisheng@163.com", 20, true);
        final String ignoreUserJsonString = gson.toJson(ignoreUser);
        System.out.println(ignoreUserJsonString);
        // {"name":"Chisheng Chen","email":"chisheng@163.com","age":20,"isDeveloper":true}
        final IgnoreUser deserializableIgnoreUser = gson.fromJson(ignoreUserJsonString, IgnoreUser.class);
        System.out.println(deserializableIgnoreUser);
        // GsonDemo.IgnoreUser(name=Chisheng Chen, email=null, age=20, isDeveloper=true)
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class User implements Serializable {
        private String name;
        private String email;
        private Integer age;
        private Boolean isDeveloper;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class ComplexUser implements Serializable {
        private String name;
        private String email;
        private Integer age;
        private Boolean isDeveloper;
        private Address address;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class Address implements Serializable {
        private String nation;
        private String city;
        private String street;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class VariousUser implements Serializable {
        @SerializedName(value = "fullName")
        // 有时候传的是fullName，有时候传的是name，这时该怎么办呢？
        // @SerializedName 接受两个参数，value 和 alternate ，顾名思义，alternate 是备选变量名
        // @SerializedName(value = "name", alternate="fullName")
        private String name;
        private String email;
        private Integer age;
        private Boolean isDeveloper;
    }

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    private static class IgnoreUser implements Serializable {

        /*
         * Default set is deserialize is true and serialize is true.
         * All filed is serialize, but email do not deserialize.
         */

        @Expose(deserialize = true)
        private String name;
        @Expose(deserialize = false, serialize = true)
        private String email;
        @Expose
        private Integer age;
        @Expose(serialize = true)
        private Boolean isDeveloper;
    }

}
